qemu: Queue mouse clicks.
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 11 Feb 2008 09:57:38 +0000 (09:57 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 11 Feb 2008 09:57:38 +0000 (09:57 +0000)
qemu doesn't enqueue mouse events, just records the latest mouse
state. This can cause some lost mouse double clicks if the events are
not processed fast enought. This patch implements a simple queue for
left mouse click events.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
tools/ioemu/hw/usb-hid.c
tools/ioemu/sdl.c

index e9479773134e98175829de8a2f6821e46b1850ed..78b48b8dbb2bd813f8b47d6245b3ca91ba6f0459 100644 (file)
@@ -224,15 +224,37 @@ static const uint8_t qemu_tablet_hid_report_descriptor[] = {
         0xC0,       /* End Collection */
 };
 
+static int currentbutton = 0;
+typedef struct _mouseclick {
+    int button_state;
+    struct _mouseclick *next;
+} mouseclick; 
+static mouseclick mousequeue[20];
+static mouseclick *head = mousequeue;
+static mouseclick *tail = mousequeue;
+
 static void usb_mouse_event(void *opaque,
                             int dx1, int dy1, int dz1, int buttons_state)
 {
     USBMouseState *s = opaque;
 
+    if (s->status_changed == 1){
+        //A mouse event is lost
+        if (buttons_state != currentbutton && tail->next != head) {
+            //A left click event is lost: let's add it to the queue
+            //counter++;
+            tail->button_state = buttons_state;
+            tail = tail->next;
+        }
+    }
+    else {
+        s->buttons_state = buttons_state;
+    }
+
     s->dx += dx1;
     s->dy += dy1;
     s->dz += dz1;
-    s->buttons_state = buttons_state;
+    currentbutton = buttons_state;
     s->status_changed = 1;
 }
 
@@ -240,11 +262,24 @@ static void usb_tablet_event(void *opaque,
                             int x, int y, int dz, int buttons_state)
 {
     USBMouseState *s = opaque;
+    
+    if (s->status_changed == 1){
+        //A mouse event is lost
+        if (buttons_state != currentbutton && tail->next != head) {
+            //A left click event is lost: let's add it to the queue
+            //counter++;
+            tail->button_state = buttons_state;
+            tail = tail->next;
+        }
+    }
+    else {
+        s->buttons_state = buttons_state;
+    }
 
     s->x = x;
     s->y = y;
     s->dz += dz;
-    s->buttons_state = buttons_state;
+    currentbutton = buttons_state;
     s->status_changed = 1;
 }
 
@@ -493,10 +528,17 @@ static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p)
             else if (s->kind == USB_TABLET)
                 ret = usb_tablet_poll(s, p->data, p->len);
 
-            if (!s->status_changed)
+            if (!s->status_changed) {
                 ret = USB_RET_NAK;
-            else
-                s->status_changed = 0;
+            } else {
+                if (head != tail) {
+                    s->buttons_state = head->button_state;
+                    head = head->next;
+                }
+                else {
+                    s->status_changed = 0;
+                }
+            }
 
         } else {
             goto fail;
@@ -567,6 +609,14 @@ int usb_mouse_load(QEMUFile *f, void *opaque, int version_id)
 USBDevice *usb_tablet_init(void)
 {
     USBMouseState *s;
+    int i;
+    
+    for (i = 0; i < 19; i++) {
+        mousequeue[i].button_state = 0;
+        mousequeue[i].next = &(mousequeue[i + 1]);
+    }
+    mousequeue[i].button_state = 0;
+    mousequeue[i].next = mousequeue;
 
     s = qemu_mallocz(sizeof(USBMouseState));
     if (!s)
@@ -591,6 +641,14 @@ USBDevice *usb_tablet_init(void)
 USBDevice *usb_mouse_init(void)
 {
     USBMouseState *s;
+    int i;
+    
+    for (i = 0; i < 19; i++) {
+        mousequeue[i].button_state = 0;
+        mousequeue[i].next = &(mousequeue[i + 1]);
+    }
+    mousequeue[i].button_state = 0;
+    mousequeue[i].next = mousequeue;
 
     s = qemu_mallocz(sizeof(USBMouseState));
     if (!s)
index 4d6d73a6a12de4e568cfb145394d7d4d89d0b03c..d2af24752b65511b04198cca380ce27442d76d5a 100644 (file)
@@ -259,11 +259,9 @@ static void sdl_grab_end(void)
     sdl_update_caption();
 }
 
-static void sdl_send_mouse_event(int dz)
+static void sdl_send_mouse_event(int dx, int dy, int dz, int state)
 {
-    int dx, dy, state, buttons;
-    state = SDL_GetRelativeMouseState(&dx, &dy);
-    buttons = 0;
+    int buttons = 0;
     if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
         buttons |= MOUSE_EVENT_LBUTTON;
     if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
@@ -425,11 +423,19 @@ static void sdl_refresh(DisplayState *ds)
         case SDL_MOUSEMOTION:
             if (gui_grab || kbd_mouse_is_absolute() ||
                 absolute_enabled) {
-                sdl_send_mouse_event(0);
+                int dx, dy, state;
+                state = SDL_GetRelativeMouseState(&dx, &dy);
+                sdl_send_mouse_event(dx, dy, 0, state);
             }
             break;
-        case SDL_MOUSEBUTTONDOWN:
         case SDL_MOUSEBUTTONUP:
+            if (gui_grab || kbd_mouse_is_absolute()) {
+                int dx, dy, state;
+                state = SDL_GetRelativeMouseState(&dx, &dy);
+                sdl_send_mouse_event(dx, dy, 0, state);
+            }
+            break;
+        case SDL_MOUSEBUTTONDOWN:
             {
                 SDL_MouseButtonEvent *bev = &ev->button;
                 if (!gui_grab && !kbd_mouse_is_absolute()) {
@@ -439,16 +445,19 @@ static void sdl_refresh(DisplayState *ds)
                         sdl_grab_start();
                     }
                 } else {
-                    int dz;
+                    int dx, dy, dz, state;
                     dz = 0;
+                    state = SDL_GetRelativeMouseState(&dx, &dy);
 #ifdef SDL_BUTTON_WHEELUP
-                    if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
+                    if (bev->button == SDL_BUTTON_WHEELUP) {
                         dz = -1;
-                    } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
+                    } else if (bev->button == SDL_BUTTON_WHEELDOWN) {
                         dz = 1;
+                    } else {
+                        state = bev->button | state;
                     }
 #endif               
-                    sdl_send_mouse_event(dz);
+                    sdl_send_mouse_event(dx, dy, dz, state);
                 }
             }
             break;